package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.json.JSONUtil;
import com.aliyun.iot20180120.Client;
import com.aliyun.iot20180120.models.*;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.zzyl.base.PageResponse;
import com.zzyl.base.ResponseResult;
import com.zzyl.config.AliIoTConfigProperties;
import com.zzyl.constant.CacheConstants;
import com.zzyl.dto.DeviceDto;
import com.zzyl.dto.DevicePageQueryDto;
import com.zzyl.entity.Device;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.DeviceMapper;
import com.zzyl.service.DeviceService;
import com.zzyl.vo.DeviceDataGraphVo;
import com.zzyl.vo.DeviceVo;
import com.zzyl.vo.ProductVo;
import org.bouncycastle.operator.MacCalculatorProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class DeviceServiceImpl implements DeviceService {

    @Autowired
    private Client client;

    @Autowired
    private AliIoTConfigProperties aliIoTConfigProperties;

    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    @Autowired
    private DeviceMapper deviceMapper;

    @Override
    public void queryProductList() {
        QueryProductListRequest request = new QueryProductListRequest();
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        request.setCurrentPage(1);
        request.setPageSize(100);
        QueryProductListResponse queryProductListResponse = null;
        try {
            queryProductListResponse = client.queryProductList(request);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        if (queryProductListResponse.getBody().success){
            List<QueryProductListResponseBody.QueryProductListResponseBodyDataListProductInfo> productInfo = queryProductListResponse.getBody().getData().getList().getProductInfo();
            //集合的产品数据放入到redis中
            redisTemplate.opsForValue().set(CacheConstants.PRODUCT_LIST, JSONUtil.toJsonStr(productInfo));
        }
    }


    @Override
    public List<ProductVo> allProduct() {
        String s = redisTemplate.opsForValue().get(CacheConstants.PRODUCT_LIST);
        List<ProductVo> list = JSONUtil.toList(s,ProductVo.class);
        return list;
    }

    @Override
    public ResponseResult registerDevice(DeviceDto deviceDto){
        //1.设备名称查询数据库设备，重复
        int count = deviceMapper.queryDevice(deviceDto.getDeviceName());
        if (count > 0) {
            throw new BaseException(BasicEnum.DEVICE_NAME_EXIST);
        }
        //2.物联网新增设备
        RegisterDeviceRequest registerDeviceRequest = new RegisterDeviceRequest();
        registerDeviceRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        registerDeviceRequest.setDeviceName(deviceDto.getDeviceName());
        registerDeviceRequest.setProductKey(deviceDto.getProductKey());
        registerDeviceRequest.setNickname(deviceDto.getNickname());
        RegisterDeviceResponse response = null;
        try {
            response =client.registerDevice(registerDeviceRequest);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        if (!response.getBody().success){
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }

        //3.插入mysql设备数据
        Device device = BeanUtil.toBean(deviceDto, Device.class);
        device.setIotId(response.getBody().getData().getIotId()); //注册设备成功之后会有设备id

        //物联网平台查询产品名称
        QueryProductRequest queryProductRequest = new QueryProductRequest();
        queryProductRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        queryProductRequest.setProductKey(deviceDto.getProductKey());
        QueryProductResponse queryProductResponse = null;

        try {
            queryProductResponse = client.queryProduct(queryProductRequest);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        if (!queryProductResponse.getBody().success){
            throw new BaseException(BasicEnum.IOT_QUERY_PRODUCT_ERROR);
        }
        //set 产品名称
        device.setProductName(queryProductResponse.getBody().getData().getProductName());

        if (deviceDto.getLocationType().equals("0")){
            device.setPhysicalLocationType(-1);
        }
        //插入数据
        try {
            device.setHaveEntranceGuard(0);
            deviceMapper.insert(device);
        } catch (Exception e) {
            //插入错误，删除注册的设备
            DeleteDeviceRequest request = new DeleteDeviceRequest();
            request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
            request.setIotId(device.getIotId());
            request.setProductKey(device.getProductKey());
            request.setDeviceName(device.getDeviceName());
            DeleteDeviceResponse deleteDeviceResponse = null;
            try {
                deleteDeviceResponse = client.deleteDevice(request);
            } catch (Exception ex) {
                throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
            }
            if (!deleteDeviceResponse.getBody().getSuccess()){
                throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
            }
        }
        return ResponseResult.success();
    }

    @Override
    public PageResponse<DeviceVo> pageQueryDevice(DevicePageQueryDto devicePageQueryDto) {
        //1.设置分页条件
        PageHelper.startPage(devicePageQueryDto.getPageNum(),devicePageQueryDto.getPageSize());
        //2.调用mapper根据条件去数据库查询设备
        Page<DeviceVo> deviceVos = deviceMapper.pageQueryDevice(devicePageQueryDto.getDeviceName(),
                devicePageQueryDto.getLocationType(),devicePageQueryDto.getProductKey());
        //3.转换成PageResponse返回
        return PageResponse.of(deviceVos, DeviceVo.class);
    }

    @Override
    public DeviceVo queryDeviceDetail(DeviceDto deviceDto) {
        //查询数据库
        DeviceVo deviceVo = deviceMapper.queryDeviceDetail(deviceDto.getIotId());
        //查询iot
        QueryDeviceDetailRequest request = new QueryDeviceDetailRequest();
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        request.setProductKey(deviceDto.getProductKey());
        request.setIotId(deviceVo.getIotId());
        QueryDeviceDetailResponse queryDeviceDetailResponse = null;
        try {
            queryDeviceDetailResponse = client.queryDeviceDetail(request);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }
        if (!queryDeviceDetailResponse.getBody().success){
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }
        QueryDeviceDetailResponseBody.QueryDeviceDetailResponseBodyData data = queryDeviceDetailResponse.getBody().getData();
        //两者合并成一个对象
        BeanUtil.copyProperties(data,deviceVo, CopyOptions.create().ignoreNullValue());
        return deviceVo;
    }

    @Override
    public QueryDevicePropertyStatusResponseBody.QueryDevicePropertyStatusResponseBodyData queryDevicePropertyStatus(QueryDevicePropertyStatusRequest request) throws Exception {
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());

        QueryDevicePropertyStatusResponse queryDevicePropertyStatusResponse = client.queryDevicePropertyStatus(request);
        if (!queryDevicePropertyStatusResponse.getBody().success){
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_PROPERTY_STATUS_ERROR);
        }
        QueryDevicePropertyStatusResponseBody.QueryDevicePropertyStatusResponseBodyData data = queryDevicePropertyStatusResponse.getBody().getData();
        return data;
    }

    @Override
    public Map<String, String> queryThingModelPublished(QueryThingModelPublishedRequest request) throws Exception {
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        QueryThingModelPublishedResponse queryThingModelPublishedResponse = client.queryThingModelPublished(request);
        if (!queryThingModelPublishedResponse.getBody().success){
            throw new BaseException(BasicEnum.IOT_QUERY_THING_MODEL_PUBLISHED_ERROR);
        }
        String thingModelJson = queryThingModelPublishedResponse.getBody().getData().thingModelJson;
        Map<String, String> map = new HashMap<>();
        map.put("thingModelJson",thingModelJson);
        return map;
    }

    @Override
    public void UpdateDevice(DeviceDto deviceDto) throws Exception {
        Device device = BeanUtil.toBean(deviceDto, Device.class);

        //先更新数据库
        deviceMapper.UpdateDevice(device);

        BatchUpdateDeviceNicknameRequest request = new BatchUpdateDeviceNicknameRequest();
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        List<BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo> deviceNicknameInfo = new ArrayList<>();
        BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo data = new BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo();
        data.setIotId(deviceDto.getIotId());
        data.setProductKey(deviceDto.getProductKey());
        data.setNickname(deviceDto.getNickname());

        deviceNicknameInfo.add(data);
        request.setDeviceNicknameInfo(deviceNicknameInfo);
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        BatchUpdateDeviceNicknameResponse batchUpdateDeviceNicknameResponse = client.batchUpdateDeviceNickname(request);
        if (!batchUpdateDeviceNicknameResponse.getBody().success){
            throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
        }
    }

    @Override
    public void DeleteDevice(DeviceDto deviceDto) throws Exception {
        //删除数据库
        deviceMapper.delete(deviceDto.getIotId());
        //删除iot
        DeleteDeviceRequest request = new DeleteDeviceRequest();
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        request.setProductKey(deviceDto.getProductKey());
        request.setIotId(deviceDto.getIotId());
        DeleteDeviceResponse deleteDeviceResponse = client.deleteDevice(request);
        if (!deleteDeviceResponse.getBody().success){
            throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
        }
    }

    @Override
    public List<DeviceDataGraphVo> queryDeviceDataListByDay(String iotId, String functionId, Long startTime, Long endTime) {
        LocalDateTime startDate = LocalDateTimeUtil.of(startTime);
        LocalDateTime endDate = LocalDateTimeUtil.of(endTime);
        List<DeviceDataGraphVo> deviceDataGraphVoList = deviceMapper.queryDeviceDataListByDay(iotId,functionId,startDate,endDate);
        Map<String, Double> map = deviceDataGraphVoList.stream().collect(Collectors.toMap(DeviceDataGraphVo::getDateTime, DeviceDataGraphVo::getDataValue));
        //{"00:00:77 ; 11:00 : 0.0"}
        //24时间空集合
        List<DeviceDataGraphVo> dateTimeList = DeviceDataGraphVo.dayInstance(startDate);
        // [{00:00:77 ; 11:00 :0.0}]
        dateTimeList.forEach(deviceDataGraphVo -> {
            Double dateValue = map.get(deviceDataGraphVo.getDateTime());
            if (dateValue != null){
                deviceDataGraphVo.setDataValue(dateValue);
            }
        });
        return dateTimeList;
    }

    @Override
    public List<DeviceDataGraphVo> pageQueryAlertData(String iotId, String functionId, Long startTime, Long endTime) {
        LocalDateTime startDate = LocalDateTimeUtil.of(startTime);
        LocalDateTime endDate = LocalDateTimeUtil.of(endTime);
        List<DeviceDataGraphVo> deviceDataGraphVoList = deviceMapper.pageQueryAlertData(iotId,functionId,startDate,endDate);
        Map<String, Double> map = deviceDataGraphVoList.stream().collect(Collectors.toMap(DeviceDataGraphVo::getDateTime, DeviceDataGraphVo::getDataValue));
        List<DeviceDataGraphVo> deviceDataGraphVoList1 = DeviceDataGraphVo.dayInstance(startDate);
        deviceDataGraphVoList1.forEach(deviceDataGraphVo -> {
            Double dateValue = map.get(deviceDataGraphVo.getDateTime());
            if (dateValue != null){
                deviceDataGraphVo.setDataValue(dateValue);
            }
        });
        return deviceDataGraphVoList1;
    }


}













